const app = getApp()
var util = require('./util.js');
var dataParse = require('./dataParse.js');
var event = require('./event.js');
const sMD5 = require('./spark-md5.js');
var aes = new util.AEScrypt('123456123456abcd', 'ABCDEF1234123412')
var data = {
  searching: false,
  isAvailable: false,
  isToasting: false,
  devicesList: [],
  connectedDevice: [],
  pcgNum: 0,  //数据发送的包数
  sendTime: 0, //当前数据包的发送次数
  canSend: true,
  BLEValueChange: false,
  reConnect:0, //重连次数
  reCreateBLE: false
}

function SearchBLE() {
  wx.closeBluetoothAdapter({
    success: function (res) {
      console.log(res)
      wx.openBluetoothAdapter({
        success: function (res) {
          console.log(res)
          wx.getBluetoothAdapterState({
            success: function (res) {
              console.log(res)
              if (!res.discovering && res.available) {
                wx.startBluetoothDevicesDiscovery({
                  allowDuplicatesKey: false,
                  success: function (res) {
                    if (app.globalData.bletype == 0 || app.globalData.bletype == 1)
                    {
                      wx.showLoading({
                        title: '正在搜索设备',
                      })
                    }
                    console.log(res)
                    data.searching = true
                    data.devicesList = []
                    data.connectedDevice = []
                  },
                  fail: function () {
                    event.$fire('ready-event')
                    event.$fire('upgrade-ready-event')
                  }
                })
                setTimeout(function () {
                  if (data.searching) {
                    wx.hideLoading();
                    wx.showToast({
                      title: '未发现此设备',
                      duration: 1000,
                      image: '/images/fail.png'
                    })
                    wx.stopBluetoothDevicesDiscovery();
                    event.$fire('ready-event')
                    event.$fire('upgrade-ready-event')
                  }
                }, 10000)
              }
            },
            fail: function () {
              event.$fire('ready-event')
              event.$fire('upgrade-ready-event')
            }
          })
        },
        fail: function (res) {
          data.searching = false
          console.log(res)
          event.$fire('ready-event')
          event.$fire('upgrade-ready-event')
          wx.showModal({
            title: '提示',
            content: '请检查手机蓝牙是否打开',
            showCancel: false,
            success: function (res) {}
          })
        }
      })
    },
    fail: function () {
      event.$fire('ready-event')
      event.$fire('upgrade-ready-event')
    }
  })
}
/**搜索设备列表 */
function Search() {
  closeConnectedDev().then(() => {
    SearchBLE()
  })
  .catch(()=>{
    SearchBLE()
  })
}

/**监听寻找到新设备 */
wx.onBluetoothDeviceFound(function (devices) { //监听寻找到新设备的事件
  //剔除重复设备，兼容不同设备API的不同返回值
  var isnotexist = true
  if (devices.deviceId && devices.name != '') {
    if (devices.advertisData) {
      devices.advertisData = app.buf2hex(devices.advertisData)
    } else {
      devices.advertisData = ''
    }
    console.log('111', devices)
    for (var i = 0; i < data.devicesList.length; i++) {
      if (devices.deviceId == data.devicesList[i].deviceId) {
        isnotexist = false
      }
    }
    if (isnotexist) {
      data.devicesList.push(devices)
      if (devices.localName === app.globalData.BLE.deviceName) {
        Connect(devices.deviceId);
      }
    }
  } else if (devices.devices && devices.devices[0].name != '') {
    if (devices.devices[0].advertisData) {
      devices.devices[0].advertisData = app.buf2hex(devices.devices[0].advertisData)
    } else {
      devices.devices[0].advertisData = ''
    }
    console.log('222', devices.devices[0])
    for (var i = 0; i < data.devicesList.length; i++) {
      if (devices.devices[0].deviceId == data.devicesList[i].deviceId) {
        isnotexist = false
      }
    }
    if (isnotexist) {
      data.devicesList.push(devices.devices[0])
      if (devices.devices[0].localName === app.globalData.BLE.deviceName) {
        Connect(devices.devices[0].deviceId);
      }
    }
  } else if (devices[0] && devices[0].name != '') {
    if (devices[0].advertisData) {
      devices[0].advertisData = app.buf2hex(devices[0].advertisData)
    } else {
      devices[0].advertisData = ''
    }
    console.log('333', devices[0])
    for (var i = 0; i < devices_list.length; i++) {
      if (devices[0].deviceId == data.devicesList[i].deviceId) {
        isnotexist = false
      }
    }
    if (isnotexist) {
      data.devicesList.push(devices[0])
      if (devices[0].localName === app.globalData.BLE.deviceName) {
        Connect(devices[0].deviceId);
      }
    }
  }
  app.globalData.BLE.devicesList = data.devicesList
})

function closeConnectedDev(params) {
  return new Promise(function (resolve, reject) {
    wx.getConnectedBluetoothDevices({
      success(res) {
        console.log(res)
        if (res.devices.length > 0) {
          wx.closeBLEConnection({
            deviceId: res.devices[0].deviceId,
            success: function (res) {
              console.log(res);
              resolve()
            },
            fail: function () {
              event.$fire('ready-event')
              event.$fire('upgrade-ready-event')
              resolve()
            }
          })
        } else {
          resolve()
        }
      },
      fail(res) {
        console.log(res)
        resolve()
      }
    })
  })
}
/**连接指定设备 */
function Connect(deviceId) {
  wx.stopBluetoothDevicesDiscovery({
    success: function (res) {
      console.log(res)
      data.searching = false
      // that.setData({
      //   searching: false
      // })
    },
    fail: function () {
      event.$fire('ready-event')
      event.$fire('upgrade-ready-event')
    },
    complete: function () {
      data.reCreateBLE = true
      createBLEConnection(deviceId)
    }
  })
}

function createBLEConnection(deviceId) {
  wx.createBLEConnection({
    deviceId: deviceId,
    timeout: 6000,
    success: async function (res) {
      console.log(res)
      wx.hideLoading()
      // app.globalData.BLE.connected = true
      app.globalData.BLE.connectedDeviceId = deviceId
      await timeout(2000)
      NotifyBLE()
    },
    fail: function (res) {
      console.log(res)
      if (data.reCreateBLE) {
        data.reCreateBLE = false
        createBLEConnection(deviceId)
      } else {
        wx.hideLoading()
        event.$fire('ready-event')
        event.$fire('upgrade-ready-event')
        wx.showModal({
          title: '提示',
          content: '连接失败',
          showCancel: false
        })
      }
    }
  })
}

function NotifyBLE(options) {
  wx.getBLEDeviceServices({
    deviceId: app.globalData.BLE.connectedDeviceId,
    success: function (res) {
      console.log("getBLEDeviceServices success", res.services)
      app.globalData.BLE.services = res.services

      for (let i = 0; i < res.services.length; i++) {
        wx.getBLEDeviceCharacteristics({
          deviceId: app.globalData.BLE.connectedDeviceId,
          serviceId: res.services[i].uuid,
          success: function (re) {
            var services_uuid = res.services[i].uuid
            console.log("success", i, services_uuid, re)
            app.globalData.BLE.characteristics = re.characteristics

            for (let i = 0; i < app.globalData.BLE.characteristics.length; i++) {
              if (app.globalData.BLE.characteristics[i].properties.notify) {
                var characteristics_id = app.globalData.BLE.characteristics[i].uuid
                wx.notifyBLECharacteristicValueChange({
                  state: true,
                  deviceId: app.globalData.BLE.connectedDeviceId,
                  serviceId: services_uuid,
                  characteristicId: app.globalData.BLE.characteristics[i].uuid,
                  success: async function (res) {
                    console.log('启用notify成功', services_uuid, characteristics_id, res)
                    app.globalData.BLE.servicesId = services_uuid
                    app.globalData.BLE.characteristicsId = characteristics_id
                    console.log("bletype:", app.globalData.bletype)
                    if (app.globalData.bletype == 0) {
                      // data.pcgNum == 0
                      event.$fire('send-open-event')
                    } else if (app.globalData.bletype == 1) {
                      // data.pcgNum == 0
                      event.$fire('send-open-event-tmp')
                    } else if (app.globalData.bletype == 2) {
                      // data.pcgNum == 0
                      await timeout(2000)
                      event.$fire('upgrade-request-event')
                    } else if (app.globalData.bletype == 3) {
                      // data.pcgNum == 90
                      await timeout(2000)
                      event.$fire('upgrade-data-event')
                    } else if (app.globalData.bletype == 4) {
                      // data.pcgNum == 0
                      event.$fire('upgrade-finish-event')
                    }
                  },
                  fail: function (res) {
                    console.log('启用notify失败', i, services_uuid, res)
                    event.$fire('ready-event')
                    event.$fire('upgrade-ready-event')
                  }
                })
              }
            }
          },
          fail: function (res) {
            console.log('fail', i, tmp_uuid, res)
            event.$fire('ready-event')
            event.$fire('upgrade-ready-event')
          }
        })
      }
    },
    fail: function () {
      event.$fire('ready-event')
      event.$fire('upgrade-ready-event')
    }
  })
}

wx.onBLEConnectionStateChange(function (res) {
  console.log("onBLEConnectionStateChange success", res.connected)
  app.globalData.BLE.connected = res.connected
  event.$fire('BLE-connected-event', res.connected)
})

/**
 * @description: 蓝牙报文下发内容
 * @param: pn 协议号
 *            登录 心跳 用户信息 控制信息 配网信息 临时密码 OTA请求 OTA数据收发 OTA完成
 *            0x01 0x02  0x03    0x05    0x06    0x07    0x08      0x09      0x10
 *         Content 信息内容
 *            控制信息：Content[0] 操作类型, Content[1] 操作对象, Content[2] 操作对象号
 *            临时密码：Content[0] 起始时间, Content[1] 结束时间, Content[2] 管理员密码
 *            OTA数据收发：Content[0] 升级包序号, Content[1] 升级数据包
 *            OTA完成：Content[0] 数据包长度
 * @return: 0:发送成功， -1: 发送失败
 */
async function sendMsg(pn, ID, content, sn) {
  // console.log("sendMsg,pn:", pn, ID, content, sn)
  var length = 0             //要发送的数据长度
  var Data                   //要发送的数据
  var result = -3             //返回的结果

  if (pn == 5) {
    Data = new ArrayBuffer(3)
    buf = new Uint8Array(Data)
    buf[0] = content[0]
    buf[1] = content[1]
    buf[2] = content[2]
    length = Data.byteLength
  } else if (pn == 7) {
    Data = new ArrayBuffer(11)
    buf = new Uint8Array(Data)
    buf[0] = (content.bTime & 0xff000000) >> 24
    buf[1] = (content.bTime & 0x00ff0000) >> 16
    buf[2] = (content.bTime & 0x0000ff00) >> 8
    buf[3] = (content.bTime & 0x000000ff)
    buf[4] = (content.eTime & 0xff000000) >> 24
    buf[5] = (content.eTime & 0x00ff0000) >> 16
    buf[6] = (content.eTime & 0x0000ff00) >> 8
    buf[7] = (content.eTime & 0x000000ff)
    buf[8] = (content.secret & 0xff0000) >> 16
    buf[9] = (content.secret & 0x00ff00) >> 8
    buf[10] = (content.secret & 0x0000ff)
    length = Data.byteLength
  } else if (pn == 9) {
    length = content.byteLength
  } else if (pn == 10) {
    Data = new ArrayBuffer(4)
    buf = new Uint8Array(Data)
    buf[0] = (content & 0xff000000) >> 24
    buf[1] = (content & 0x00ff0000) >> 16
    buf[2] = (content & 0x0000ff00) >> 8
    buf[3] = content & 0x000000ff
    length = Data.byteLength
  } else{
    Data = null
    length = 1
  }
  // console.log("length:", length, '   data.pcgNum:', data.pcgNum)
  data.pcgNum = 0
  for (; length > (data.pcgNum * 1024);) {
    if (app.globalData.stopUpgrade) {
      return -3
    }
    // console.log('pcgNum1:',data.pcgNum) 
    // console.log('data.sendTime', data.sendTime)
    if(data.sendTime == 0){
      if (pn == 9) {
        // console.log('pcgNum2:', data.pcgNum)
        Data = null
        Data = await Package(length, content)           //发送OTA数据的需要对数据进行处理
      }
      var Content = bleSendProtocol(pn, ID, Data, sn)                 //对要发送的内容进行处理（起始位、结束位、CRC校验等）
    // console.log(content)
    }
    
    for (let pos = 0; pos < Content.byteLength;) {                     //发送数据，20字节发送一次
      await timeout(20)
      if (app.globalData.stopUpgrade) {
        return -3
      }
      var ret = await sendBytes(pos, Content, Content.byteLength)
      // console.log('111:',ret)
      if(ret.result == 0){
        data.reConnect = 0
        pos = ret.pos
        continue
      } else if(ret.result == -2){
        console.log(data.reConnect)
        if (data.reConnect < 5){
          data.reConnect++
          return -2
        }
        else{
          data.reConnect = 0
          return -1
        }
      }
    }
    if (app.globalData.stopUpgrade) {
      return -3
    }
    result = await MsgResp(15)                       //接收消息
    // console.log('11result:', result)
    if(pn == 9){  //OTA升级数据
      if ((result == -1) && (data.sendTime == 0)) {     //第一次未收到消息，重发一次
        data.sendTime++
      } else if ((result == -1) && (data.sendTime == 1)) {  //第二次未收到消息，返回-1
        data.sendTime = 0
        return -1
      } else {                                           //收到消息，发送下一包
        data.sendTime = 0
        data.pcgNum++
      }
    }else{
      if ((result == -1) || (result != pn)) return -1
      else { data.pcgNum++}
    }
    
  }
  
  return result
}

/**
 * OTA数据分包,每包1K
 */
function Package(length, Data){
  //数据内容
  var pcgData
  if ((data.pcgNum + 1) * 1024 <= length) {
    pcgData = Data.slice(data.pcgNum * 1024, (data.pcgNum + 1) * 1024)
  } else {
    pcgData = Data.slice(data.pcgNum * 1024)
  }
  var bufData = new Uint8Array(pcgData)

  //数据MD5
  var spark = new sMD5.ArrayBuffer();
  spark.append(pcgData);
  var pcgMD5 = spark.end(false);
  // console.log(pcgMD5)
  var pcgMD5Buffer = new ArrayBuffer(20)
  var bufMD5 = new Uint8Array(pcgMD5Buffer);
  bufMD5[0] = 0x55;
  bufMD5[1] = 0x55;
  bufMD5[2] = 0xaa;
  bufMD5[3] = 0xaa;
  for (var l = 4; l < 20; l++) {
    var str = parseInt(pcgMD5.substr((l - 4) * 2, 2), 16)
    bufMD5[l] = str
  }

  //要发送的数据content
  var len = pcgData.byteLength + pcgMD5Buffer.byteLength
  var pcgContent = new ArrayBuffer(len + 1)
  var buf0 = new Uint8Array(pcgContent, 0, 1)
  var buf1 = new Uint8Array(pcgContent, 1, pcgData.byteLength)
  var buf2 = new Uint8Array(pcgContent, pcgData.byteLength + 1)
  buf0[0] = data.pcgNum + 1
  buf1.set(bufData)
  buf2.set(bufMD5)

  return pcgContent
}

/**
 * 发送20字节
 */
async function sendBytes(pos, Data, len){
  // console.log('sendBytes,pos:',pos)
  let tmpBuffer
  if((pos + 20) <= len){
    tmpBuffer = Data.slice(pos, pos + 20)
    pos += 20
  } else {
    tmpBuffer = Data.slice(pos)
    pos += len
  }
  var result = await new Promise((resolve,reject) => {
    wx.writeBLECharacteristicValue({
      deviceId: app.globalData.BLE.connectedDeviceId,
      serviceId: app.globalData.BLE.servicesId,
      characteristicId: app.globalData.BLE.characteristicsId,
      value: tmpBuffer,
      success: function (res) {
        console.log('发送成功:', 'data:', app.buf2hex(tmpBuffer), '  pos:', pos)
        resolve({
          result: 0,
          pos: pos
        }) 
      },
      fail: function (res) {
        console.log('发送失败', res)
        resolve({
          result: -2
        }) 
      }
    })
  })
  console.log('result send:', result)
  return result
}

/**
 * 接收数据
 */
async function MsgResp(num) { 
  // var retn = -1
  var parser = new dataParse.DataParse()
  var devInfo = new util.DevInfo()
  var lockOpInfo = new util.LockOpInfo()
  try {
    var value = wx.getStorageSync('deviceInfo')
    if (value) {
      // Do something with return value
      ///  console.log(111)
    } else {
      wx.setStorageSync('deviceInfo', devInfo)
      ///  console.log(222)
    }
  } catch (e) {
    // Do something when catch error
    //  console.log(333)
  }
  try {
    var value = wx.getStorageSync('lockOpInfo')
    if (value) {

    } else {
      wx.setStorageSync('lockOpInfo', lockOpInfo)
    }
  } catch (e) {

  }
  var result = -1
  // for(let i = 0; i < num; i ++) {
  //   await timeout(200)
  data.BLEValueChange = false
  result = await new Promise((resolve) => {
    // console.log("111")
    wx.onBLECharacteristicValueChange(async function (res) {
      // console.log('222:',Date.now())
      app.globalData.BLE.bleData.push(new Uint8Array(res.value))
      data.BLEValueChange = true
      if (data.BLEValueChange) {
        var length = app.globalData.BLE.bleData.length
        // console.log("length:", length)
        if (length > 0) {
          var msg = app.globalData.BLE.bleData.readBytes(length)
          for (let i = 0; i < length; i++) {
            if (parser.parser_put_data(msg[i]) == 0) {
              // console.log("parser_put_data success")
              var tmpMsg = parser.parser_get_data(msg[i])
              console.log('recv:', app.buf2hex(tmpMsg))
              var obj = CheckMsg(tmpMsg)
              if (obj.ret == 1) {
                switch (obj.pn) {
                  case 1:
                    break
                  case 2:
                    break
                  case 3:
                    GetDeviceInfo(obj.content)
                    break
                  case 4:
                    GetLockOpInfo(obj.content)
                    break
                  case 5:
                    result = 5
                    break
                  case 7:
                    result = 7
                    break
                  case 8:
                    result = 8
                    break
                  case 9:
                    await event.$fire('upgrade-progress', data.pcgNum)
                    result = 9
                    break
                  case 10:
                    result = 10
                    break
                  default:
                    break
                }
              //  data.BLEValueChange = false
                console.log('msgresp:', result)
                resolve(result)
              }
              else {
                // resolve(-1)
                result = -1
                resolve(result)
              }
            }
          }
        }
      }
    })
    setTimeout(() => {
      if (!data.BLEValueChange) {
        resolve(-1)
      }
    }, 3000);
    // console.log('result:', result)
  })
  return result
}

/**
 * @description: 蓝牙报文下发协议
 * @param: pn协议号,ID终端ID,Content信息内容,sn序列号
 *         起始位 包长度 协议号 信息内容 信息序列号 错误校验 停止位
 *           2      2     1       n        2        2      2
 * @return: Message
 */
function bleSendProtocol(pn, ID, Content, sn) {
  // console.log(pn, ID, Content, sn)
  var len = Content ? Content.byteLength : 0
  let Message = new ArrayBuffer(len + 15)

  let start = new Uint8Array(Message, 0, 2)
  let pcgLength = new Uint8Array(Message, 2, 2)
  let protocolNo = new Uint8Array(Message, 4, 1)
  let terminalID = new Uint8Array(Message, 5, 4)
  let content = new Uint8Array(Message, 9, len)
  let sequenceNo = new Uint8Array(Message, len + 9, 2)
  let crc = new Uint8Array(Message, len + 11, 2)
  let end = new Uint8Array(Message, len + 13)

  start[0] = 0x55
  start[1] = 0x55
  pcgLength[0] = (len + 9) >> 8
  pcgLength[1] = len + 9
  protocolNo[0] = pn
  if (ID) {
    terminalID[0] = ID[0]
    terminalID[1] = ID[1]
    terminalID[2] = ID[2]
    terminalID[3] = ID[3]
  } else {
    terminalID[0] = 0x00
    terminalID[1] = 0x00
    terminalID[2] = 0x00
    terminalID[3] = 0x00
  }
  if (Content) {
    let tmpBuf = new Uint8Array(Content)
    content.set(tmpBuf)
  }
  if (sn) {
    sequenceNo[0] = ((sn >> 8) & 0x00ff)
    sequenceNo[1] = (sn & 0x00ff)
  } else {
    sequenceNo[0] = 0x00
    sequenceNo[1] = 0x00
  }
  var buf = Message.slice(2, len + 11)
  var crcbuf = new Uint8Array(buf)
  var crc16 = util.GetCrc16(crcbuf, len + 9)
  // console.log('crc:', app.buf2hex(buf), crcbuf)
  crc[0] = ((crc16 >> 8) & 0x00ff)
  crc[1] = (crc16 & 0x00ff)
  end[0] = 0xaa
  end[1] = 0xaa

  return Message
}

/**
 * 检查回复报文
 */
function CheckMsg(data) {
  var len = data.length
  if (len < 11) {
    return {
      ret: 0
    }
  }
  /**起始位 */
  if (data[0] != 0x55 || data[1] != 0x55) {
    return {
      ret: -1
    }
  }
  /**停止位 */
  if (data[len - 2] != 0xaa || data[len - 1] != 0xaa) {
    return {
      ret: -2
    }
  }
  /**包长度 */
  // if (data[2] != len - 5) {
  if ((data[2] != ((len - 6) >> 8) & 0x00ff) || (data[3] != ((len - 6) & 0x00ff))) {
    return {
      ret: -3
    }
  }
  var n = len - 11
  var crc16 = util.GetCrc16(data.slice(2, n + 7), n + 5)
  /**错误校验 */
  if ((data[n + 7] != ((crc16 >> 8) & 0x00ff)) ||
    (data[n + 8] != (crc16 & 0x00ff))) {
    return {
      ret: -4
    }
  }
  if (data[4] != 8) {
    data.canSend = false
  }
  return {
    ret: 1,
    pn: data[4],
    content: data.slice(5, n + 5),
    sn: data.slice(n + 5, n + 7)
  }
}

function GetDeviceInfo(data) {
  var tmpdevInfo = wx.getStorageSync('deviceInfo')
  console.log('GetDeviceInfo before', tmpdevInfo)
  tmpdevInfo.deviceInfo[0].usedNum = data[4]
  tmpdevInfo.deviceInfo[1].usedNum = data[8]
  tmpdevInfo.deviceInfo[2].usedNum = data[22]

  /**totalNum:总位数, num:详情数组下标, offset:比特偏移（0-7）, index:消息体起始下标 */
  var totalNum, num, offset, index
  index = [5, 9, 23]
  for (let i = 0; i < tmpdevInfo.deviceInfo.length; i++) {
    totalNum = tmpdevInfo.deviceInfo[i].totalNum
    num = 0
    offset = 0
    while (totalNum > num) {
      if (tmpdevInfo.ifInited) {
        tmpdevInfo.deviceInfo[i].detailInfo[num].data = (data[index[i]] >> offset) & 0x01
      } else {
        tmpdevInfo.deviceInfo[i].detailInfo[num] = {
          data: (data[index[i]] >> offset) & 0x01,
          backup: ''
        }
      }
      num++
      offset++
      if (offset >= 8) {
        offset = 0
        index[i]++
      }
    }
  }
  /*
  wx.setStorage({
    key: 'deviceInfo',
    data: deviceInfo,
    success: function (res) {
      console.log('异步保存成功')
    }
  })*/
  tmpdevInfo.ifInited = true
  console.log('GetDeviceInfo after', tmpdevInfo)
  wx.setStorageSync('deviceInfo', tmpdevInfo)
}

function GetLockOpInfo(data) {
  var tmpInfo = wx.getStorageSync('lockOpInfo')
  console.log('GetLockOpInfo', tmpInfo)
  var time
  time = {
    year: data[6],
    month: data[7],
    day: data[8],
    hour: data[9],
    min: data[10],
    sec: data[11]
  }

  var lockState = data[4]
  var operateResult = data[5]
  var opreateType = data[12]
  var userNum = data[13]
  var infoItem = {
    lockState: lockState,
    operateResult: operateResult,
    time: time,
    opreateType: opreateType,
    userNum: userNum
  }
  tmpInfo.info.push(infoItem)
  wx.setStorageSync('lockOpInfo', tmpInfo)
}

/**
 * 延时函数
 */
function timeout(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

module.exports = {
  Search: Search,
  sendMsg: sendMsg,
  searching: data.searching
}